<?php
/**
* DIXon Generation 1 - JavaScript Client Pages
* 
* PHP Bindings for PHP 5.2.x and above
* 
* Copyright (c) 2008, Artem Ploujnikov
* All rights reserved.
* 
* Redistribution and use in source and binary forms, with or without modification, 
* are permitted provided  that the following conditions are met:
* 
*  * Redistributions of source code must retain the above copyright notice, this 
*    list of conditions and the following disclaimer.
*  * Redistributions in binary form must reproduce the above copyright notice, this 
* 	 list of conditions and the following disclaimer in the documentation and/or 
*    other materials provided with the distribution.
* *  Neither the name of Artem Ploujnikov nor the names of the project's contributors 
* 	 may be used to endorse or promote products derived from this software without 
*    specific prior written permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
* POSSIBILITY OF SUCH DAMAGE. 
*/

/**
* The main request handler for DiXon JavaScript Client Pages.
* This handler is responsible for etracting page names from
* the query string and then compiling and delivering
* those pages
* 
* @author Artem Ploujnikov 
*/
class DiXon_JSClientPageHandler {
	const PageRegex = '/^page\d+$/';
	
	private static $systemPages = array(
		'System/Error.xml'
	);
	
	/**
	* The DiXon configuration used by this instance
	* 
	* @var DiXon_Configuration
	*/
	private $configuration;
	
	/**
	* An XsltProcessor instance pre-loaded with the DiXon
	* compiler
	* 
	* @var XSLTProcessor
	*/
	private $compiler;	
	
	/**
	* The destination where compiled JavaScript Client
	* Pages will be output
	* 
	* @var IOutputStream
	*/
	private $output;
	
	/**
	* Creates a new JSCP page handler
	* 
	* @param DiXon_Configuration $configuration the configuration to
	* 	be used. If ommitted, the default configuration file will
	* 	be read and used by this handler.
	*/
	public function __construct(DiXon_Configuration $configuration = null, IOutputStream $output = null) {
		if ($configuration === null) {
			$this->configuration = DiXon_Configuration::getInstance();
		} else {
			$this->configuration = $configuration;
		}
		if ($output === null) {
			$this->output = new DiXon_StandardOutputStream();
		} else {
			$this->output = $output;
		}
		$this->loadCompiler();
	}
	
	/**
	* Loads the DiXon compiler stylesheet
	*/
	private function loadCompiler() {
		$this->compiler = new XSLTProcessor();
		$stylesheetDocument = new DOMDocument();
		$stylesheetDocument->resolveExternals = true;
		$stylesheetDocument->load(
			DIXON_ROOT 
			. DIRECTORY_SEPARATOR
			. $this->configuration->getPath(DiXon_Configuration::CompilerStylesheetPath)
		);
		$this->compiler->importStylesheet($stylesheetDocument);	
	}
		
	/**
	* Processes an HTTP request for JavaScript Client Pages
	*/
	public function processRequest() {
		try {
			array_walk(
				self::$systemPages,
				array($this, 'servePage')
			);
			DiXon_PageError::enableErrorPage();
			$pages = $this->getPages();
			array_walk(
				$pages,
				array($this, 'servePage')
			);
		} catch(Exception $e) {
			$pageError = DiXon_PageError::fromException($e);
			$scriptWriter = new DiXon_ScriptWriter(new DiXon_StandardOutputStream());
			$pageError->displayInScript($scriptWriter);
		}
	}
	
	/**
	* Returns the list of pages that will be served
	* 
	* @return $pages
	*/
	private function getPages() {
		$keys = array_filter(
			array_keys($_GET),
			array($this, 'isPageKey')
		);
		
		return array_merge(
			array_map(
				array($this, 'getRequestParameter'),
				$keys
			)
		);
	}
	
	/**
	* Serves a single page to the client
	* 
	* @param string $pageName the name of the page to serve
	*/
	private function servePage($pageName) {
		$page = new JSClientPage(
			$this->compiler, 
			$pageName, 
			$this->configuration);
		$page->output($this->output);
	}
	
	/**
	* Determines whether the specified query string parameter
	* name is a request for a JSCP page
	* 
	* @return string
	*/
	private function isPageKey($name) {
		return preg_match(self::PageRegex, $name);
	}
	
	/**
	* Returns the query string parameter with the specified name.
	* If no such parameter is specified, this method returns null
	* 
	* @return string
	*/
	private function getRequestParameter($name) {
		return (isset($_GET[$name])) ? $_GET[$name] : null;
	}
}

?>